import { AxiosResponse, InternalAxiosRequestConfig } from "axios";
import httpRequest from "..";
import { refreshAccessToken } from "../modules/refreshToken";

export const ACCESS_TOKEN_KEY = "access_token";
export const REFRESH_TOKEN_KEY = "refresh_token";
export const UNAUTHORIZED_STATUS_CODE = 401;

// token 工具函数

/**
 * 获取token
 * @param key token的key
 * @returns {string}accessToken
 */
export function getToken(key: string) {
    return localStorage.getItem(key);
}

/**
 * 存储token到本地
 * @param key token的key
 * @param token token的值
 */
export function setToken(key: string, token: string) {
    localStorage.setItem(key, token);
}

// 拦截器

/**
 * 请求拦截器：只要本地有access token，所有请求的请求头就携带上它。(对于没有采用单点登录方案的系统，access token就是普通 token)
 * @param {InternalAxiosRequestConfig}config
 * @returns {InternalAxiosRequestConfig}config
 */
export function setAccessTokenRequestInterceptor(config: InternalAxiosRequestConfig) {
    if (config.headers && !config.headers._isRefreshAccessTokenRequest) {
        config.headers.authorization = `Bearer ${getToken(ACCESS_TOKEN_KEY)}`;
    }
    return config;
}

/**
 * 响应拦截器：只要服务器响应了 token，就保存下来到本地，无论是 access token 还是 refresh token。
 * 当接口因权限拒绝或者本地计算 access token 过期，则就去拿 refresh token 无感刷新 access token。
 * @param {AxiosResponse}res
 * @returns {AxiosResponse}res
 */
export async function getTokenResponseInterceptor(res: AxiosResponse) {
    // 假设服务器将token放在响应体中返回

    // 保存授权 token，也就是 access token 或者普通的 token
    if (res.data.data?.accessToken) {
        const token = res.data.data.accessToken.replace("Bearer ", "");
        setToken(ACCESS_TOKEN_KEY, token);
    }

    // 保存 refresh token
    if (res.data.data?.refreshToken) {
        const refreshToken = res.data.data.refreshToken.replace("Bearer ", "");
        setToken(REFRESH_TOKEN_KEY, refreshToken);
    }

    // 请求业务接口没有权限，说明 access token 过期，需要刷新 token
    if (res.data.code === UNAUTHORIZED_STATUS_CODE && !res.config.headers._isRefreshAccessTokenRequest) {
        // 请求服务器获取最新access token，当前拦截器递归保存token
        const isRefreshSuccess = await refreshAccessToken();
        if (isRefreshSuccess) {
            // 刷新 access token 成功，装配新 access token 后拿到 axios 实例重新发起请求
            res.config.headers.Authorization = `Bearer ${getToken(ACCESS_TOKEN_KEY)}`;
            const response = await httpRequest.getInstance().request(res.config);
            return response;
        } else {
            // 刷新失败，refresh token 过期，跳转登录页面重新登录
            window.location.hash = "/login";
            // window.location.href = "/login";
        }
    }

    return res;
}
